const Router = require('express').Router;
const assert = require('assert');
const moment = require('moment');
const asyncUtils = require('express-async-handler');
const utils = require('../utils/utils.js');
const NodeRSA = require('node-rsa');
const CryptoJS = require('crypto-js');
const Key = require('../models/key.js');
const VCode = require('../models/vCode.js');
const User = require('../models/user.js');
const {Token, expiresTime} = require('../models/token.js');
const router = new Router();

const AESKey = 'li';
//注册
router.post("/signUp", asyncUtils(async (req, res) => {
  let {account, pwd, nickname, vCode, vId, kId} = req.body;
  //参数验证
  assert.ok(account && typeof account === 'string' && account.trim() !== '', '请输入有效的账号');
  // assert.ok(pwd && typeof pwd === 'string' && pwd.trim() !== '', '请输入有效的密码');
  assert.ok(nickname && typeof nickname === 'string' && nickname.trim() !== '', '请输入有效的昵称');
  assert.ok(vCode && typeof vCode === 'string' && vCode.trim() !== '', '请输入有效的验证码');
  assert.ok(vId && typeof vId === 'string' && vId.trim() !== '', '验证错误');
  assert.ok(kId && typeof kId === 'string' && kId.trim() !== '', 'key id 不能为空');

  //比对验证码是否正确
  //先查找验证码
  const v = await VCode.findById(vId);
  if (!v) throw new Error("验证码已失效");
  if (v.code.toLowerCase() !== vCode.toLowerCase()) throw new Error('验证码错误');

  const k = await Key.findById(kId);
  if (!k) throw new Error("kId未找到");

  //rsa 用私钥解密
  let r = decryptRSA(k, pwd);

  //用aes 进行加密
  pwd = CryptoJS.AES.encrypt(r, AESKey).toString();

  //存入数据库
  const u = await new User({
    account, pwd, nickname
  }).save();

  k.uId = u.id.toString();
  await k.save();
  res.json(utils.success());
}));
//登录
router.post('/signIn', asyncUtils(async (req, res) => {
  let {account, pwd} = req.body;
  assert.ok(account && typeof account === 'string' && account.trim() !== '', '请输入有效的账号');
  const user = await User.findOne({account});
  if (!user) throw new Error('账号错误');

  //验证密码
  //AES 解密
  let _pwd = CryptoJS.AES.decrypt(user.pwd, AESKey).toString(CryptoJS.enc.Utf8);
  //用私钥解密
  //查询私钥
  let k = await Key.findOne({uId: user._id.toString()});
  if (!k) throw new Error('私钥不存在');

  let r = decryptRSA(k, pwd);
  if (r !== _pwd) throw new Error('密码错误');

  //保存登录状态
  //创建登陆令牌
  const token = await Token.findOneAndUpdate({uId: user._id.toString()}, {
    expiresTime: Date.now() + expiresTime,
    updateTime: new Date()
  }, {
    upsert: true,
    new: true
  });

  //写入 cookie
  res.cookie('token', token._id.toString(), {httpOnly: true, maxAge: expiresTime});

  res.json(utils.success());

}));
//获取公钥
router.post('/getPk', asyncUtils(async (req, res) => {
  const key = new NodeRSA({b: 512});
  key.generateKeyPair(2048, 65537);
  const pk = key.exportKey('pkcs1-public');
  const sk = key.exportKey('pkcs1-private');
  const r = await new Key({
    pk, sk
  }).save();

  res.json(utils.success({pk, kId: r._id}));

}));

//通过账号查询公钥
router.post('/getPkByAccount', asyncUtils(async (req, res) => {
  let {account} = req.body;
  assert.ok(account && typeof account === 'string' && account.trim() !== '', '请输入有效的账号');
  const user = await User.findOne({account});
  if (!user) throw new Error('账号错误');
  let k = await Key.findOne({uId: user._id.toString()});
  res.json(utils.success(k.pk));
}));

//获取用户信息
router.post('/info', asyncUtils(async (req, res) => {
  const {token} = req.cookies;
  if (!token) {
    res.json(utils.success());
    return;
  }

  const t = await Token.findById(token);
  if (!t) {
    res.json(utils.success());
    return;
  }
  if (moment(t.expirationTime).isBefore(moment())) {
    await Token.deleteOne({_id: token});
    res.cookie('token', '', {maxAge: 0});
    res.json(utils.success());
  } else {
    const user = await User.findById(t.uId, '-pwd -createTime -updateTime');
    res.json(utils.success(user));
  }
}));

router.post('/signOut', asyncUtils(async (req, res) => {
  const {token} = req.cookies;
  assert.ok(token, 'token 不存在');

  await Token.deleteOne({_id: token});
  res.cookie('token', '', {maxAge: 0});
  res.json(utils.success());

}));


function decryptRSA(k, buffer) {
  const rsa = new NodeRSA({b: 512});
  rsa.importKey(k.pk, 'pkcs1-public');
  rsa.importKey(k.sk, 'pkcs1-private');
  let r = rsa.decrypt(Buffer.from(buffer.data));
  return r.toString();
}

module.exports = router;
